什么是 webpack?
webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理。
我们可以直接使用 require(XXX) 的形式来引入各模块,即使它们可能需要经过编译(比如JSX和sass),但我们无须在上面花费太多心思,因为 webpack 有着各种健全的加载器(loader)在默默处理这些事情,因为以近期 Github 上各大主流的(React相关)项目来说,它们仓库上所展示的示例已经是基于 webpack 来开发的,比如 React-Bootstrap 和 Redux链接:https://github.com/gaearon/redux
webpack的官网是 http://webpack.github.io/ ,文档地址是 http://webpack.github.io/docs/ ,想对其进行更详细了解的可以点进去瞧一瞧。
webpack 的优势
其优势主要可以归类为如下几个:
webpack 是以 commonJS 的形式来书写脚本,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
能被模块化的不仅仅是 JS 了。
开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等。
扩展性强,插件机制完善,特别是支持 React 热插拔(见 react-hot-loader )的功能让人眼前一亮。
我们谈谈第一点。以 AMD/CMD 模式来说,鉴于模块是异步加载的,所以我们常规需要使用 define 函数来帮我们搞回调:
|
|
另外为了可以兼容 commonJS 的写法,我们也可以将 define 这么写:
|
|
然而对 webpack 来说,我们可以直接在上面书写 commonJS 形式的语法,无须任何 define (毕竟最终模块都打包在一起,webpack 也会最终自动加上自己的加载器):
|
|
即使你保留了之前 define 的写法也是可以滴,毕竟 webpack 的兼容性相当出色,方便你旧项目的模块直接迁移过来。
安装和配置
一. 安装
我们常规直接使用 npm 的形式来安装:
初始化 npm 环境
首先保证有 node 和 npm 环境,运行node -v和npm -v查看
进入项目目录,运行npm init按照步骤填写最终生成package.json文件,所有使用 npm 做依赖管理的项目,根目录下都会有一个这个文件,该文件描述了项目的基本信息以及一些第三方依赖项(插件)。
|
|
安装完成之后,查看package.json可看到多了 devDependencies 和 dependencies 两项,根目录也多了一个node_modules文件夹。
–save 和 –save-dev 的区别
npm i时使用–save和–save-dev,可分别将依赖(插件)记录到package.json中的dependencies和devDependencies下面。
dependencies下记录的是项目在运行时必须依赖的插件,
常见的例如react jquery等,即及时项目打包好了、上线了,这些也是需要用的,否则程序无法正常执行。
devDependencies下记录的是项目在开发过程中使用的插件,
例如这里我们开发过程中需要使用webpack打包,而我在工作中使用fis3打包,但是一旦项目打包发布、上线了之后,webpack和fis3就都没有用了,可卸磨杀驴。
延伸一下,我们的项目有package.json,其他我们用的项目如webpack也有package.json,
见./node_modules/webpack/package.json,其中也有devDependencies和dependencies。
当我们使用npm i webpack时,
./node_modules/webpack/package.json中的dependencies会被 npm 安装上,而devDependencies也没必要安装。
配置 webpack.config.js
为了提高学习效率,webpack最最基础的用法,webpack.config.js这个配置文件详细的讲解一下,
文件格式
webpack.config.js 就是一个普通的 js 文件,符合 commonJS 规范。最后输出一个对象,即module.exports = {…}
输入 & 输出
这个比较基础,不过需要新建./app/index.jsx作为入口文件,目前项目中只有这一个入口文件。不过 webpack 支持多个入口文件,可查阅文档。
输出就是一个bundle.js,js 和 css 都在里面,不过只有在开发环境下才用,发布代码的时候,肯定不能只有这么一个文件,接下来会讲到。
module
针对不同类型的文件,使用不同的loader,当然使用之前要安装,
例如npm i style-loader css-loader –save-dev。该项目代码中,我们用到的文件格式有:js/jsx 代码、css/less 代码、图片、字体文件。
less 是 css 的语法糖,可以更高效低冗余的写 css,不熟悉的朋友可去官网看看,非常简单。
在加载 css/less 时用到了postcss,主要使用autoprefixer功能,帮助自动加 css3 的浏览器前缀,非常好用。
编译 es6 和 jsx 语法时,用到家喻户晓的babel,另外还需增加一个.babelrc的配置文件。
plugins
使用 html 模板(需要npm i html-webpack-plugin –save-dev),这样可以将输出的文件名(如./bundle.js)自动注入到 html 中,不用我们自己手写。手写的话,一旦修改就需要改两个地方。
使用热加载和自动打开浏览器插件
devServer
对 webpack-dev-server 的配置
npm start
在 package.json 中,输入以下代码,将这一串命令封装为npm start,这样就可以运行项目代码了。
代码中NODE_ENV=dev代表当前是开发环境下,这里的”dev”可被 js 代码中的process.env.NODE_ENV得到并做一些其他处理。
定义环境全局变量
以下定义,可使得代码通过DEV得到当前是不是开发模式。
打开./app/util/localStore.js可以看到if (DEV) { console.error(‘localStorage.getItem报错, ‘, ex.message) },即只有开发环境下才提示error,发布之后就不会提示了。(因为发布的命令中用到NODE_ENV=production)
配置 webpack.production.config.js
开发环境下,可以不用考虑系统的性能,更多考虑的是如何增加开发效率。而发布系统时,就需要考虑发布之后的系统的性能,包括加载速度、缓存等。下面介绍发布用配置代码和开发用的不一样的地方。
发布到 ./build 文件夹中
path: __dirname + “/build”,
vendor
将第三方依赖单独打包。即将 node_modules 文件夹中的代码打包为 vendor.js 将我们自己写的业务代码打包为 app.js。这样有助于缓存,因为在项目维护过程中,第三方依赖不经常变化,而业务代码会经常变化。
md5后缀
为每个打包出来的文件都加md5后缀,例如”/js/[name].[chunkhash:8].js”,可使文件强缓存。
分目录
打包出来的不同类型的文件,放在不同目录下,例如图片文件将放在img/目录下
Copyright
自动为打包出来的代码增加 copyright 内容
分模块
new webpack.optimize.OccurenceOrderPlugin(),
压缩代码
使用 Uglify 压缩代码,其中warnings: false是去掉代码中的 warning
分离 css 和 js 文件
开发环境下,css 代码是放在整个打包出来的那个 bundle.js 文件中的,发布环境下当然不能混淆在一起,使用new ExtractTextPlugin(‘/css/[name].[chunkhash:8].css’),将 css 代码分离出来。
npm run build
打开package.json,查看以下代码。npm start和npm run build分别是运行代码和打包项目。另外,”start”、”test”可以不用run。
这两个命令主要有以下区别:
前者中默认使用 webpack.config.js 作为配置文件,而后者中强制使用 webpack.production.config.js 作为配置文件
前者NODE_ENV=dev而后者NODE_ENV=production,标识不同的环境。而这个”dev” “production”可以在代码中通过process.env.NODE_ENV获取。
最小化压缩 React
以下配置可以告诉 React 当前是生产环境,请最小化压缩 js ,即把开发环境中的一些提示、警告、判断通通去掉,直流以下发布之后可用的代码。
二. 配置
每个项目下都必须配置有一个 webpack.config.js ,它的作用如同常规的 gulpfile.js/Gruntfile.js ,就是一个配置项,告诉 webpack 它需要做什么。
我们看看下方的示例:
⑴ plugins 是插件项,这里我们使用了一个 CommonsChunkPlugin 的插件,它用于提取多个入口文件的公共脚本部分,然后生成一个 common.js 来方便多页面之间进行复用。
⑵ entry 是页面入口文件配置,output 是对应输出项配置(即入口文件最终要生成什么名字的文件、存放到哪里),其语法大致为:
该段代码最终会生成一个 page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下。
⑶ module.loaders 是最关键的一块配置。它告知 webpack 每一种文件都需要使用什么加载器来处理:
⑷ 最后是 resolve 配置,这块很好理解,直接写注释了:
关于 webpack.config.js 更详尽的配置可以参考这里。http://webpack.github.io/docs/configuration.html